package com.zbowen.juc.utils;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Random;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;

public class ParkingLot {

    private static final Logger LOGGER = LoggerFactory.getLogger(ParkingLot.class);
    private static final SimpleDateFormat SDF = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    private static final Random RAND = new Random();

    public static void main(String[] args) {
        int parkingSpaceCount = 3;
        Semaphore semaphore = new Semaphore(parkingSpaceCount);
        ReentrantLock lock = new ReentrantLock(true);
        for (int i = 0; i < 10; i++) {
            new Thread(new Car("Car" + (i + 1), semaphore, lock)).start();
            try {
                TimeUnit.MILLISECONDS.sleep(RAND.nextInt(500));
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }

    static class Car implements Runnable {

        private String carId;
        private Semaphore semaphore;
        private ReentrantLock lock;

        public Car(String carId, Semaphore semaphore, ReentrantLock lock) {
            this.carId = carId;
            this.semaphore = semaphore;
            this.lock = lock;
        }

        @Override
        public void run() {
            long begin = System.currentTimeMillis();
            LOGGER.info("[{}]准备进入停车场。", carId);
            // 不断尝试获取许可
            while (true) {
                try {
                    lock.lock();
                    // 尝试获取许可
                    if (semaphore.tryAcquire()) {
                        lock.unlock();
                        // 生成随机停车时长
                        int waitTime = RAND.nextInt(20) + 10;
                        LOGGER.info("[{}]成功进入停车场，预计停车[{}]秒。", carId, waitTime);
                        try {
                            TimeUnit.SECONDS.sleep(waitTime);
                        } catch (InterruptedException e) {
                            throw new RuntimeException(e);
                        }
                        LOGGER.info("[{}]离开停车场。", carId);
                        break;
                    } else {
                        lock.unlock();
                        // 超过5000毫秒就不在等待
                        long end = System.currentTimeMillis();
                        if (end - begin > 5000) {
                            LOGGER.info("[{}]等待超时，气愤驱车离开！等等开始时间：[{}]", carId, SDF.format(new Date(begin)));
                            break;
                        }
                    }
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }
}
